import requests
import json
import os


class DingTalkRobot:
    def __init__(self, webhook, secret=None):
        """
        初始化钉钉机器人
        :param webhook: 机器人的Webhook地址
        :param secret: 机器人的密钥（可选，用于签名验证）
        """
        self.webhook = webhook
        self.secret = secret

    def send_text_message(self, content, at_mobiles=None, is_at_all=False):
        """
        发送文本消息
        :param content: 消息内容
        :param at_mobiles: 被@的用户手机号列表
        :param is_at_all: 是否@所有人
        :return: 接口响应结果
        """
        if not content:
            raise ValueError("消息内容不能为空")

        data = {
            "msgtype": "text",
            "text": {
                "content": content
            },
            "at": {
                "atMobiles": at_mobiles or [],
                "isAtAll": is_at_all
            }
        }

        return self._send_request(data)

    def upload_file(self, file_path):
        """
        上传文件到钉钉服务器，获取media_id
        :param file_path: 本地文件路径
        :return: media_id
        """
        if not os.path.exists(file_path):
            raise FileNotFoundError(f"文件不存在: {file_path}")

        if not os.path.isfile(file_path):
            raise IsADirectoryError(f"不是一个文件: {file_path}")

        # 从webhook中提取access_token
        access_token = self._extract_access_token()
        if not access_token:
            raise ValueError("无法从webhook中提取access_token")

        upload_url = f"https://oapi.dingtalk.com/media/upload?access_token={access_token}&type=file"

        with open(file_path, 'rb') as f:
            files = {'media': f}
            response = requests.post(upload_url, files=files)

        result = response.json()
        if result.get('errcode') != 0:
            raise Exception(f"文件上传失败: {result.get('errmsg')}")

        return result.get('media_id')

    def send_file(self, file_path):
        """
        发送文件
        :param file_path: 本地文件路径
        :return: 接口响应结果
        """
        media_id = self.upload_file(file_path)

        data = {
            "msgtype": "file",
            "file": {
                "media_id": media_id
            }
        }

        return self._send_request(data)

    def _send_request(self, data):
        """
        发送请求到钉钉接口
        :param data: 消息数据
        :return: 接口响应结果
        """
        headers = {'Content-Type': 'application/json;charset=utf-8'}

        # 如果有secret，需要进行签名处理
        if self.secret:
            import time
            import hmac
            import hashlib
            import base64
            timestamp = str(round(time.time() * 1000))
            secret_enc = self.secret.encode('utf-8')
            string_to_sign = f'{timestamp}\n{self.secret}'
            string_to_sign_enc = string_to_sign.encode('utf-8')
            hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
            sign = base64.b64encode(hmac_code).decode('utf-8')
            url = f"{self.webhook}&timestamp={timestamp}&sign={sign}"
        else:
            url = self.webhook

        response = requests.post(url, headers=headers, data=json.dumps(data))
        result = response.json()

        if result.get('errcode') != 0:
            raise Exception(f"消息发送失败: {result.get('errmsg')}")

        return result

    def _extract_access_token(self):
        """
        从webhook中提取access_token
        :return: access_token
        """
        from urllib.parse import urlparse, parse_qs
        parsed_url = urlparse(self.webhook)
        query_params = parse_qs(parsed_url.query)
        return query_params.get('access_token', [None])[0]


if __name__ == "__main__":
    # 替换为你的机器人Webhook和secret
    WEBHOOK = "https://oapi.dingtalk.com/robot/send?access_token=db6323f6953d47ff2c18d4660639e3b9e8aba005569aa233d64989c17a4ec316"
    # SECRET = "SECd35c7b74e6b57cfd10b5136a5d66a5ad02e427b229dbee44aca263a3a79f9afe"  # 如果没有设置安全设置，可以设为None
    # 初始化机器人
    # WEBHOOK = WEBHOOK
    SECRET = None
    robot = DingTalkRobot(WEBHOOK, SECRET)

    try:
        # 发送文本消息
        print("发送文本消息...")
        text_response = robot.send_text_message(
            "这是一条来自Python脚本的测试消息",
            at_mobiles=["15910613235"],  # 替换为实际要@的手机号
            is_at_all=False
        )
        print("文本消息发送成功:", text_response)

        # 发送文件
        print("\n发送文件...")
        file_path = "1.txt"  # 替换为实际的文件路径
        file_response = robot.send_file(file_path)
        print("文件发送成功:", file_response)

    except Exception as e:
        print("发生错误:", str(e))
